<?php

/**
 * lrn框架之对象管理小组件
 * 
 * 本文件的思路参考过以下程序，在此一并致谢！
 * - xweibo{@link http://x.weibo.com}
 * - lotusphp{@link http://code.google.com/p/lotusphp/}
 * 
 * @author Horse Luke<horseluke@126.com>
 * @copyright Horse Luke, 2010
 * @license the Apache License, Version 2.0 (the "License"). {@link http://www.apache.org/licenses/LICENSE-2.0}
 * @version $Id: object.php 140 2010-11-20 14:48:08Z horseluke@126.com $
 * @package lrn_framework
 */
class lrn_util_object{
    
    protected static $_instance = array();
    
    /**
     * 静态方法getInstanceOf的别名
     * 
     * @uses self::getInstanceOf
     * @param string $classname 类名
     * @param string $index 索引，默认等同于$classname
     * @param string $method 初始化时，调用什么方法。若参数为'__construct'，则表示new $classname($args[0], $args[1], ......);
     * @param array $args 初始化调用方法的参数
     * @return object
     */
    public static function singleton( $classname, $index = null, $method = '', $args = array() ){
        return self::getInstanceOf( $classname, $index, $method, $args );
    }
    
    
    /**
     * 获取指定对象或者指定索引对象的单个实例。没有则初始化一个并且存储起来。
     * 
     * @uses self::store
     * @param string $classname 类名
     * @param string $index 索引，默认等同于$classname
     * @param string $method 初始化时，调用什么方法。若参数为'__construct'，则表示new $classname($args[0], $args[1], ......);
     * @param array $args 初始化调用方法的参数
     * @return object
     */
    public static function getInstanceOf( $classname, $index = null, $method = '', $args = array() ){
        if (empty( $index )) {
            $index = $classname;
        }
        if (isset( self::$_instance[$index] )) {
            $instance = self::$_instance[$index];
        } else {
            //新建类
            if (strtolower( $method ) == '__construct') {
                $prm = array();
                foreach ($args as $i => $v) {
                    $prm[] = "\$args[{$i}]";
                }
                eval( "\$instance = new " . $classname . " (" .
                             implode( ",",  $prm ) .
                       ");" );
            } else {
                $instance = new $classname();
                if (! empty( $method ) && method_exists( $instance, $method )) {
                    if (! empty( $args )) {
                        call_user_func_array( array(&$instance, $method), $args );
                    } else {
                        $instance->$method();
                    }
                }
            }
            
            self::store( $instance, $index );
            
        }
        return $instance;
    }
    
    
    /**
     * 载入app（自定义程序）模型并返回该模型实例
     * 
     * @uses lrn::import , self::getInstanceOf
     * @param string $name 模型名称。若传入null值，则等同于默认模型lrn_model
     * @param string $index 模型实例索引。若传入布尔值false值，则表示强制新建一个模型实例；否则，则表示用该索引存储该模型实例，以便下次调用时直接返回，以节省内存空间（若传入null，则等同于用$name作索引）。
     * @param string $appPath app目录位置。不填写则表示导入APP_PATH所在的模型
     * @return object
     */
    public static function model( $name = null, $index = null, $appPath = null ){
        if (null === $name) {
            $name = 'lrn_model';
        }
        //载入模型
        if ($name != 'lrn_model') {
            if (null === $appPath) {
                lrn::import( 'app.model.'. $name );
            } else {
                lrn::import( 'model.'. $name, $appPath );
            }
        }
        //是否新建一个模型实例？$index为false时候，则强制新建一个模型实例，并且不存储
        if (false === $index) {
            return new $name();
            //否则，则表示用该索引存储该模型实例，以便下次调用时直接返回，以节省内存空间（若传入null，则等同于用$name作索引）
        } else {
            if (null === $index) {
                $index = $name;
            }
            return self::getInstanceOf( $name, $index );
        }
    }
    
    
    /**
     * 将一个对象存储进来。
     * @param object $instance 对象实例
     * @param string $index 索引 
     * @param bool $overwrite 当该索引已经存在实例时，是否覆盖？默认为否，此时将自动抛出exception
     * @return bool
     */
    public static function store( $instance, $index, $overwrite = false ){
        
        if( isset(self::$_instance[$index]) && false == $overwrite ){
            throw new Exception('An instance has been stored in: '.$index);
        }
        
        self::$_instance[$index] = $instance;
        return true;
        
    }
    
    
}